import bcrypt
from sqlalchemy import Column, Integer, String, func, DateTime, Float, SmallInteger, JSON
from sqlalchemy.orm import relationship

from flaskr.models.application import Application
from .base import db
from flask import current_app


class User(db.Model):
    __tablename__ = 'users'
    id = Column(Integer, nullable=False, primary_key=True)
    username = Column(String(50), nullable=False, unique=True)
    password = Column(String(128), nullable=False)
    phone = Column(String(20), nullable=True)
    description = Column(String(200), nullable=True)
    credit = Column(Float, nullable=False, default=1000.0)
    department = Column(String(30), nullable=True, default="计算机科学与技术学院")
    level = Column(SmallInteger, nullable=False, default=0)
    tags = Column(JSON, nullable=True, default=[])

    created = Column(DateTime, server_default=func.now(), comment='创建时间')
    updated = Column(DateTime, server_default=func.now(),
                     onupdate=func.now(), comment='修改时间')

    missions = relationship('Mission', backref='owner')
    applications = relationship('Application', backref='applier')

    def save(self):
        db.session.add(self)
        db.session.commit()

    def check_password(self, income_password: str):
        # current_app.logger.info(
        #     "income_password: %s, self password %s", income_password, self.password)
        if not isinstance(self.password, bytes):
            encoded_password = self.password.encode()
        else:
            encoded_password = self.password
        return bcrypt.checkpw(income_password.encode(), encoded_password)

    @staticmethod
    def query_by_username(username: str):
        return User.query.filter_by(username=username).one_or_none()

    @staticmethod
    def owed_credit(identify: int):
        user = User.query_by_id(identify)
        credits = 0
        for mission in user.missions:
            remained = mission.people - len(Application.query.filter(
                Application.mission_id == mission.id, Application.state == 3).all())
            credits += remained * mission.credit_per_people

        return credits

    @staticmethod
    def query_by_id(identify: int):
        return User.query.filter_by(id=identify).one_or_none()

    @staticmethod
    def update_by_id(identify: int, attrs: dict):
        User.query.filter_by(id=identify).update(attrs)
        db.session.commit()
        return User.query_by_id(identify)

    def __repr__(self):
        return f'<User {self.username!r}>'

# 存放登出的token


class TokenBlocklist(db.Model):
    id = Column(Integer, primary_key=True)
    jti = Column(String(50), nullable=False)
    created_at = Column(DateTime, server_default=func.now(), nullable=False)

    def save(self):
        db.session.add(self)
        db.session.commit()

    @staticmethod
    def query_id_by_jti(jti: str):
        return db.session.query(TokenBlocklist.id).filter_by(jti=jti).scalar()
